package cn.com.twoke.easyproject.config;


import cn.com.twoke.easyproject.common.constant.Profile;
import cn.com.twoke.easyproject.common.response.R;
import cn.com.twoke.easyproject.common.response.ResponseCode;
import cn.com.twoke.easyproject.config.spi.GlobalErrorMessageHandler;
import cn.dev33.satoken.context.SaHolder;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.filter.SaServletFilter;
import cn.dev33.satoken.router.SaHttpMethod;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

@Slf4j
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(name = "sa-token.enabled", havingValue = "true", matchIfMissing = true)
public class SaTokenConfiguration {


    /**
     * 无需登录的接口地址集合
     */
    private static final String[] NO_LOGIN_PATH_ARR = {
            /* 主入口 */
            "/",
            /* 静态资源 */
            "/static/fonts/**",
            "/static/icons/**",
            "/favicon.ico",
            "/doc.html/**",
            "/webjars/**",
            "/swagger-resources/**",
            "/swagger-ui/**",
            "/v2/api-docs",
            "/v2/api-docs-ext",
            "/v3/api-docs/**",
            "/v3/api-docs-ext",
            "/druid/**",
            "/auth/login",
    };

    /**
     * 允许访问的角色数组
     */
    private static final String[] ROLES_ALLOWED_ACCESSED = new String[]{

    };

    /**
     * 注册 [Sa-Token 全局过滤器]
     */
    @Bean
    public SaServletFilter getSaServletFilter(GlobalErrorMessageHandler messageHandler) {
        return new SaServletFilter()
                // 指定拦截路由
                .addInclude("/**")
                .addExclude(NO_LOGIN_PATH_ARR)
                // 设置鉴权的接口
                .setAuth(r -> {
                    SaRouter.match("/**", () -> StpUtil.checkLogin());
                    SaRouter.match("/**", () -> StpUtil.checkRoleOr(ROLES_ALLOWED_ACCESSED));
                })
                // 前置函数：在每次认证函数之前执行
                .setBeforeAuth(obj -> {
                    // ---------- 设置跨域响应头 ----------
                    SaHolder.getResponse()
                            // 是否可以在iframe显示视图： DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
                             .setHeader("X-Frame-Options", "SAMEORIGIN")
                            // 是否启用浏览器默认XSS防护： 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时，停止渲染页面
                            .setHeader("X-XSS-Protection", "1; mode=block")
                            // 禁用浏览器内容嗅探
                            .setHeader("X-Content-Type-Options", "nosniff")
                            // 允许指定域访问跨域资源
//                            .setHeader("Access-Control-Allow-Origin", "*")
                            // 允许所有请求方式
                            .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
                            // 有效时间
                            .setHeader("Access-Control-Max-Age", "3600");
                            // 允许的header参数
//                            .setHeader("Access-Control-Allow-Headers", "*");

                    // 如果是预检请求，则立即返回到前端
                    SaRouter.match(SaHttpMethod.OPTIONS)
                            // OPTIONS预检请求，不做处理
                            .free(r -> {
                            }) .back();
                })

                // 异常处理
                .setError(e -> {
                    // 由于过滤器中抛出的异常不进入全局异常处理，所以必须提供[异常处理函数]来处理[认证函数]里抛出的异常
                    // 在[异常处理函数]里的返回值，将作为字符串输出到前端，此处统一转为JSON输出前端
                    SaResponse saResponse = SaHolder.getResponse();
                    saResponse.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
                    saResponse.setStatus(ResponseCode.UNAUTHORIZED.code);
                    return JSON.toJSONString(messageHandler.handle(null, ResponseCode.UNAUTHORIZED.code, ResponseCode.UNAUTHORIZED.message, e.getMessage()));
                });
    }









}
